<?php
require_once(CORE_DIR.'/include/kernel.php');

class shopCore extends kernel{

    var $member = null;
    var $is_shop = true;
    var $_err = array();
    var $ErrorSet = array();
    var $use_gzip = true;
    var $page;
    var $_errArr;

    function shopCore(){

        parent::kernel();
        
        $this->run();
    }

    function compactUrl($newurl){
        $this->_succ=true;
        header('Location: '.$newurl,true,301);
        exit;
    }

    /**
     * shop
     *
     * @access public
     * @return void
     */
    function run(){
        ob_start();
        define('IN_SHOP',true);


        $_COOKIE = isset($_COOKIE[COOKIE_PFIX])?$_COOKIE[COOKIE_PFIX]:array();

        $request = $this->parseRequest();
        
        $this->request = &$request;

        $GLOBALS['runtime'] = $request;
        if(isset($request['member'])){
            foreach($request['member'] as $k=>$v){
                $GLOBALS['runtime'][$k] = $v;
            }
        }

        $cacheAble = !(count($_POST)>0);

        if(isset($_GET['ctl'])){
            $page = &$this->_frontend($request,array(
                'controller'=>$_GET['ctl'],
                'method'=>isset($_GET['act'])?$_GET['act']:'index',
                'args'=>isset($_GET['p'])?$_GET['p']:null));
        }else{
            register_shutdown_function(array(&$this,'shutdown'));
            $page = &$this->_frontend($request);
        }

        $this->display($page);
        exit();
    }

    function match_network ($nets, $ip, $first=false) {
        $return = false;
        if (!is_array ($nets)) $nets = array ($nets);

        foreach ($nets as $net) {
            $rev = (preg_match ("/^\!/", $net)) ? true : false;
            $net = preg_replace ("/^\!/", "", $net);

            $ip_arr  = explode('/', $net);
            $net_long = ip2long($ip_arr[0]);
            $x        = ip2long($ip_arr[1]);
            $mask    = long2ip($x) == $ip_arr[1] ? $x : 0xffffffff << (32 - $ip_arr[1]);
            $ip_long  = ip2long($ip);

            if ($rev) {
                if (($ip_long & $mask) == ($net_long & $mask)) return false;
            } else {
                if (($ip_long & $mask) == ($net_long & $mask)) $return = true;
                if ($first && $return) return true;
            }
        }
        return $return;
    }

    function errorHandler($errno, $errstr, $errfile, $errline){
        $error_arr = array('no'=>$errno,'msg'=>$errstr,'file'=>$errfile,'line'=>$errline);
        if($errno == ((E_ERROR | E_USER_ERROR ) & $errno)){
            $this->_errArr[] = $error_arr;
            $this->shutdown(true);
        }elseif($errno == ((E_WARNING ) & $errno)){
            $this->_errArr[] = $error_arr;
            error_log(print_r($error_arr,1),3,HOME_DIR.'/logs/warning_log_'.date("Y-m-d").'.log');
        }
        return true;
    }

    function shutdown($halt=false){
        if($halt || !isset($this->_succ)){
            $this->_succ=true;
            $data = array('html'=>'','body'=>'','date'=>date("Y-m-d H:i:s (T)"),'fatal'=>null);
            $errorlevels = array(
                2048 => 'Error',
                1024 => 'Notice',
                512 => 'Warning',
                256 => 'Error',
                128 => 'Warning',
                64 => 'Error',
                32 => 'Warning',
                16 => 'Error',
                8 => 'Notice',
                4 => 'Error',
                2 => 'Warning',
                1 => 'Error');

            while(ob_get_level()>0){
                $data['body'] .= ob_get_contents();
                ob_end_clean();
            }

            if(!$halt){
                if($pos = strrpos($data['body'],'Fatal error')){
                    $data['fatal'].=substr($data['body'],$pos);
                }elseif($pos = strrpos($data['body'],'Parse error')){
                    $data['fatal'].=substr($data['body'],$pos);
                }
            }else{
                $err = array_pop($this->_errArr);
                $data['fatal'].= "<li class=\"err_{$err['no']}\"><b class=\"no\">{$errorlevels[$err['no']]}:</b> <span class=\"body\">{$err['msg']}<span>{$err['file']}:{$err['line']}</li>";
            }
            if($this->_errArr){
                foreach($this->_errArr as $err){
                    $data['html'].= "<li class=\"err_{$err['no']}\"><b class=\"no\">{$errorlevels[$err['no']]}:</b> <span class=\"body\">{$err['msg']}<span>{$err['file']}:{$err['line']}</li>";
                }
            }

            if($data['fatal']){
                $this->responseCode(500);
                $data['msg'] = '系统暂时发生错误，请回到首页重新访问';
                $html  = file_get_contents(CORE_DIR.'/shop/view/page/system-error.html');
                foreach($data as $k=>$v){
                    $html = str_replace('%'.$k.'%',$v,$html);
                }
                echo $html;
            }else{
                echo $data['html'].$data['body'];
            }

            if(function_exists('debug_backtrace')){
                echo '<ol>';
                $lastfile = null;
                foreach(debug_backtrace() as $trace){
                    if(isset($trace['file']) && $trace['file']!=$lastfile){
                        $lastfile = $trace['file'];
                        echo '<div style="padding-top:10px;color:#999">'.$trace['file'].':'.$trace['line'].'</div>';
                    }
                    echo '<li style="font-weight:bold">'.(isset($trace['class'])?$trace['class']:'php').'::'.$trace['function'].'()</li>';
                }
                echo '</ol>';
            }


            exit();
        }
    }

    function setCookie($name,$value,$expire=false,$path=null){
        if(!isset($this->_cookiePath) || !$this->_cookiePath){
            $cookieLife = $this->getConf('system.cookie.life');
            $this->_cookiePath = substr(PHP_SELF, 0, strrpos(PHP_SELF, '/')).'/';
            $this->_cookieLife = $cookieLife;

        }
        $this->_cookieLife = ($this->_cookieLife>0)?$this->_cookieLife:315360000;
        setCookie(COOKIE_PFIX.'['.$name.']',$value,($expire===false)?(time()+$this->_cookieLife):$expire,$this->_cookiePath);
        $_COOKIE[$name] = $value;
    }

    function display(&$pageObj){

        $this->_succ = true;
        $header_sent = headers_sent();
        //    header('Runtime: '.($this->microtime() - $this->_start));
        header('Connection: close');

        if($pageObj['cache']){
            header("Cache-Control: private");
            header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
            if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $pageObj['header']['Etag']){
                header('Etag: '.$pageObj['header']['Etag'],true,304);
                exit(0);
            }
            
//            header("Expires: " .gmdate("D, d M Y H:i:s", time() + (isset($pageObj['cachettl'])?$pageObj['cachettl']:1)). " GMT");
        }else{
            if(strpos($_SERVER["HTTP_USER_AGENT"],'MSIE 6.0') && !defined('ORDER_DOWNLOAD')){
                header("Cache-Control: no-cache"); // 强制更新
            }else{
                header("Cache-Control: no-cache, no-store, must-revalidate"); // 强制更新
            }
//            header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
            header("Expires: -1");            
            header("Pragma: no-cache");
            unset($pageObj['header']['Last-Modified']);                        
            unset($pageObj['header']['Etag']);            
        }


        foreach($pageObj['header'] as $k=>$v){
            header($k.': '.$v);
        }

        if($pageObj['gziped'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && !$header_sent){
            if(strpos(" ".$_SERVER['HTTP_ACCEPT_ENCODING'],"gzip")){
                header('Content-Encoding: gzip');
                header('Content-Length: '.$pageObj['gziped-size']);
                if (strtoupper($_SERVER['REQUEST_METHOD']) == 'HEAD') exit(0);
                echo $pageObj['gziped'];
            }elseif(strpos(" ".$_SERVER['HTTP_ACCEPT_ENCODING'],"x-gzip")){
                header('Content-Encoding: x-gzip');
                header('Content-Length: '.$pageObj['gziped-size']);
                if (strtoupper($_SERVER['REQUEST_METHOD']) == 'HEAD') exit(0);
                echo $pageObj['gziped'];
            }else{
                header('Content-Length: '.$pageObj['size']);
                if (strtoupper($_SERVER['REQUEST_METHOD']) == 'HEAD') exit(0);
                echo $pageObj['body'];
            }
        }else{
            header('Content-Length: '.$pageObj['size']);
            if (strtoupper($_SERVER['REQUEST_METHOD']) == 'HEAD') exit(0);
            echo $pageObj['body'];
        }
        exit();
    }

    function mkUrl($ctl,$act='index',$args=null,$extName = 'html'){
        return $this->realUrl($ctl,$act,$args,$extName,$this->request['base_url']);
    }

    function parseUrl($query){
        $urlData = array();
        if($query=='index.html'){
            $urlData = array('controller'=>'page','method'=>'index','args'=>array(),'type'=>'html');
        }else{
             if($pos = strpos($query,'.')){
                $type = substr($query,$pos+1);
                if($position = strpos($type,'&')){
                    $type = substr($type,0,$position);
                }
                if($position = strpos($type,'?')){
                    $type = substr($type,0,$position);
                }
                $query = substr($query,0,$pos);
            }
    
            $args = explode('-',$query);
            $act = 'index';
    
            if(($ctl = array_shift($args)) && $ctl!='index'){
                if(count($args)>0 && !is_numeric($args[count($args)-1])){
                    $act = array_pop($args);
                }
            }
            foreach($args as $k=>$v){
                $args[$k] = str_replace('|jh|','-',$v);
                $args[$k] = str_replace('|dian|','.',$args[$k]);
                $args[$k] = str_replace('|xie|','/',$args[$k]);
                $args[$k] = str_replace('|xie|','%2F',$args[$k]);
            }
    
            $urlData = array('controller'=>$ctl,'method'=>$act,'args'=>$args,'type'=>$type);

        }
        return $urlData;
    }

    function &_frontend($request,$action=null){
        require_once(CORE_DIR.'/include/func_ext.php');
        ob_start();
        if(!$action)$action = $this->parseUrl($request['query']);
        $this->request['action'] = &$action;

        require_once('shopPage.php');
        
        $controller = &$this->getController($action['controller']);
        
        $controller->action = &$action;
        $this->ctl = &$controller;

        if(!is_object($controller))$this->error(404);

        $this->use_gzip = function_exists('gzencode')?true:false;

        if(!$this->callAction($controller,$action['method'],$action['args'])){
            $urlTools = &$this->loadModel('utility/url');
            if($newurl = $urlTools->map($_SERVER['QUERY_STRING'])){
                $this->compactUrl($newurl);
            }else{
                $this->error(404);
            }
        }
        $page = array(
            'header'=>array('Content-Language'=>'utf-8'),
            'cache'=>!$controller->noCache,
            'body'=>'',
            'size'=>0,
        );

        $this->_succ = true;
        $ob_length=ob_get_level()-1;
        while(ob_get_level()>0){
            if($ob_length==ob_get_level()){
                break;
            }else{
                $ob_length=ob_get_level();
            }
            $page['size'] += ob_get_length();
            $page['body'] .= ob_get_contents();
            ob_end_clean();
        }

        if(isset($controller->cachettl)) $page['cachettl'] = $controller->cachettl; //
        if(isset($this->_expiresTime)) $page['expires'] = $this->_expiresTime;

        $page['header']['Etag'] = crc32($page['body']);
        $page['header']['Last-Modified'] = gmdate('D, d M Y H:i:s').' GMT';

        $this->_debugger['runtime'] = $this->microtime() - $this->_start;
        $this->_debugger['gzip'] = $this->use_gzip;

        $page['header']['Content-type'] = $controller->contentType;
        if($this->use_gzip){
            if($page['gziped'] = @gzencode($page['body'], 3)){
                $page['gziped-size'] = strlen($page['gziped']);
            }
        }

        return $page;
    }

    function setExpries($time){
        if($time>time()){
            $this->_expiresTime = isset($this->_expiresTime)?min($time,$this->_expiresTime):$time;
        }
        return true;
    }

    function &getController($mod){
        
        $object = false;
        $fname = CORE_DIR.'/shop/controller/'.dirname($mod).'/ctl.'.basename($mod).'.php';
        if(!is_file($fname)){
            $this->error(404,'controller not found');
        }else{
            require($fname);
            $mod_name = 'ctl_'.basename($mod);
            $object = new $mod_name($this);
            return $object;
        }
    }

    function error($code,$msg=''){
        $this->responseCode($code);
        echo $msg;
        die();
    }

    function _build_post($d,$path=null){
        $m='';
        foreach($d as $k=>$v){
            $p = $path?$path.'['.$k.']':$k;
            if(is_array($v)){
                $m .= $this->_build_post($v,$p);
            }else{
                $m .='<input type="hidden" name="'.$p.'" value="'.$v.'" />';
            }
        }
        return $m;
    }

    /*对请求进行解析
    返回数组:
    设置_GET
     */
    function parseRequest($query = null){

        if(!$query){
            $query = $_SERVER["QUERY_STRING"];
            if(!($REQUEST_URI = getenv('REQUEST_URI'))){
                if(isset($_SERVER['HTTP_X_REWRITE_URL'])){
                    $REQUEST_URI = $_SERVER['HTTP_X_REWRITE_URL']?$_SERVER['HTTP_X_REWRITE_URL']:$_SERVER['REQUEST_URI'];
                }else{
                    $REQUEST_URI = $_SERVER['REQUEST_URI'];
                }
            }
        }

        $get = null;
        if($p = strpos($query,'?')){
            $get = substr($query,$p+1);
            $query = substr($query,0,$p);
        }else{
            $p = parse_url($REQUEST_URI);
            if(isset($p['query']))$get = $p['query'];
        }
        if($get!=$query){
            parse_str($get,$get);
            $_GET = array_merge($_GET,$get);
        }

        $url_prefix = $this->base_url();

        return array(
            'base_url'=>$url_prefix,
            'member_lv'=>isset($_COOKIE['MLV'])?$_COOKIE['MLV']:-1,
            'query'=>$query?$query:'index.html',
        );
    }

    function location($url){
        if($_POST){
            $html="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
                \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
                <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en-US\" lang=\"en-US\" dir=\"ltr\">
                <head></header><body>Redirecting...";
            $html .= '<form id="splash" action="'.$url.'" method="post">'.$this->_build_post($_POST);
            $html.=<<<EOF
</form><script language="javascript">
document.getElementById('splash').submit();
</script></html>
EOF;
            echo $html;
            exit();
        }else{
            header('Location: '.$url);
            exit();
        }
    }
}
?>
